package com.javaxiaobear.base.framework.config;

import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.dao.SaTokenDaoForRedisson;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.jwt.SaJwtUtil;
import cn.dev33.satoken.jwt.StpLogicJwtForMixin;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.json.JSONUtil;
import com.javaxiaobear.base.common.utils.SecurityUtils;
import com.javaxiaobear.base.framework.security.RsaSaJwtTemplate;
import com.javaxiaobear.base.framework.web.domain.AjaxResult;
import jakarta.annotation.PostConstruct;
import java.time.Duration;
import java.util.List;
import org.redisson.api.RedissonClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * spring security配置
 *
 * @author javaxiaobear
 */
@Configuration
public class SecurityConfig implements WebMvcConfigurer {
  List<String> ignoreUrls =
      ListUtil.toList(
          "/",
          "*.html",
          "*.html",
          "*.css",
          "*.js",
          "/profile/*",
          "/login",
          "/logout",
          "/register",
          "/captchaImage",
          "/swagger-ui.html",
          "/swagger-resources/*",
          "/webjars/*",
          "/*/api-docs",
          "/druid/*");

  /** 允许匿名访问的地址 */
  @PostConstruct
  void init() {
    SaJwtUtil.setSaJwtTemplate(new RsaSaJwtTemplate());
  }

  @Bean
  public StpLogic getStpLogicJwt() {
    return new StpLogicJwtForMixin();
  }

  @Bean
  public SaTokenDaoForRedisson saTokenDaoForRedisson(RedissonClient redissonClient) {
    return new SaTokenDaoForRedisson(redissonClient) {
      @Override
      public void setObject(String key, Object object, long timeout) {
        redissonClient.getBucket(key).set(object, Duration.ofSeconds(timeout));
      }

      @Override
      public Object getObject(String key) {
        return redissonClient.getBucket(key).get();
      }

      @Override
      public <T> T getObject(String key, Class<T> classType) {
        return (T) getObject(key);
      }

      @Override
      public void updateObject(String key, Object object) {
        long expire = getTimeout(key);
        // -2 = 无此键
        if (expire == SaTokenDao.NOT_VALUE_EXPIRE) {
          return;
        }
        this.setObject(key, object, expire);
      }
    };
  }

  @Bean
  public StpInterface stpInterface() {
    return new StpInterface() {
      @Override
      public List<String> getPermissionList(Object loginId, String loginType) {
        return SecurityUtils.getPermissions(loginId);
      }

      @Override
      public List<String> getRoleList(Object loginId, String loginType) {
        return SecurityUtils.getRoles(loginId);
      }
    };
  }

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    // 注册 Sa-Token 拦截器，打开注解式鉴权功能
    registry
        .addInterceptor(new SaInterceptor())
        .addPathPatterns("/**")
        .excludePathPatterns(ignoreUrls);
  }

  @Bean
  public SaServletFilter getSaServletFilter() {
    return new SaServletFilter()
        .addInclude("/**")
        .addExclude(ignoreUrls.toArray(new String[0])) /* 排除掉 /favicon.ico */
        .setAuth(obj -> StpUtil.isLogin())
        .setError(e -> JSONUtil.toJsonStr(AjaxResult.error(401, e.getMessage())));
  }
}
